Skip to content

Commit

Permalink
+++
Browse files Browse the repository at this point in the history
  • Loading branch information
Offirmo committed Oct 3, 2024
1 parent da178a3 commit d5984cc
Show file tree
Hide file tree
Showing 13 changed files with 105 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './renderers/to_text.js'
export * from './renderers/to_html.js'

export * from './types.js'
export * from './type-guards.js'
export * from './walk.js'
export * from './renderers/common.js'
export * from './sugar/builder.js'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

6 Reasons Users Hate Your New Feature https://www.slicedbreaddesign.com/blog/6-reasons-users-hate-your-new-feature
[ ] https://skamille.medium.com/
[ ] personal MBA
Expand All @@ -9,6 +10,7 @@ average revenue per user (ARPU)
boring -- culture
boring -- plans https://skamille.medium.com/make-boring-plans-9438ce5cb053
boring -- technology https://mcfunley.com/choose-boring-technology
brand -- 6 what's? = what we stand for, what we believe in, what people we seek to engage, what distinguishes us, what we offer, what we say and show https://hbr.org/2014/06/start-ups-need-a-minimum-viable-brand
business as a by-product https://www.linkedin.com/posts/jason-fried_ive-always-thought-of-business-as-a-by-product-activity-7236805665627717632-_s96
churn
computers should adapt to users = not necessarily if the solution is good (ex. typing on a keyboard, Palm Graffiti) https://www.creativitypost.com/technology/the_memory_prediction_framework_of_intelligence_and_the_subject_of_creativi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
0-sum game
1 or 2 way door
12 steps
1st thought v.s 2nd thought
3 hardest things to say -- I was wrong, I need help, I love you -> also 10 https://kristyna.co/mindful-entrepreneurship/10-hardest-things-for-people-to-say
3 Strikes and You're Out = Californian law https://lao.ca.gov/analysis_1995/3strikes.html
3-strike pivot strategy -- Strike 1: Identify and try to address the issue directly
Expand Down Expand Up @@ -45,11 +46,10 @@ Baptists and Bootleggers https://a16z.com/ai-will-save-the-world/
base rate: The average outcome for an event over time. They’re like batting averages for life, and they work best with big sample sizes. For example, if you’re starting a business, avoid the restaurant business where margins are low and competition is high.
be prepared
bee browsing
bike-shed Effect: A group of people working on a project will fight over the most trivial ideas. They’ll ignore what’s complicated. They’ll focus too much on easy-to-understand ideas at the expense of important, but hard to talk about ideas. For example, instead of approving plans for a complicated spaceship, the team would argue over the color of the astronaut’s uniforms.
bike shed Effect: A group of people working on a project will fight over the most trivial ideas. They’ll ignore what’s complicated. They’ll focus too much on easy-to-understand ideas at the expense of important, but hard to talk about ideas. For example, instead of approving plans for a complicated spaceship, the team would argue over the color of the astronaut’s uniforms.
biographies -- Profiles in Courage https://en.wikipedia.org/wiki/Profiles_in_Courage
bonnes et mauvaises cartes
brain rot https://en.wikipedia.org/wiki/Brain_rot
brand -- 6 what's? = what we stand for, what we believe in, what people we seek to engage, what distinguishes us, what we offer, what we say and show https://hbr.org/2014/06/start-ups-need-a-minimum-viable-brand
broken window theory
bullying = Lack of consideration and empathy for those without power, Disrespectful behavior that is overt or subtle (in public or behind closed doors), Verbal aggression, sarcasm, or psychological manipulation. Unreasonable or constantly changing directives and deadlines. Singling out individuals. “Mobbing,” in which a group of people gang up on an individual
bullying = repeated pattern of offensive, intimidating, or hostile behavior(s) or language, often by a strong or other person of authority. Bullying creates a toxic atmosphere for everyone, but may be accepted by many as “part of the workplace culture”
Expand Down Expand Up @@ -236,6 +236,7 @@ Mutually Exclusive, Collectively Exhaustive (MECE) https://strategyu.co/wtf-is-m
naiveté: abus sexuels, mafia
needs / wants https://en.wikipedia.org/wiki/Need
never-Ending Now: The structure of our social media feeds blinds us to history, as it causes us to live in an endless cycle of ephemeral content consumption. The structure of the Internet pulls people away from age-old wisdom.
no conflict / safe conflict / extreme conflict
non-violence
normalisation de la déviance https://macbidouille.com/news/2024/07/13/samedi-securite-la-normalisation-de-la-deviance-suite
not for profit -- The dirty dozen myths https://www.linkedin.com/pulse/dirty-dozen-myths-profit-sector-jo-owen
Expand Down
7 changes: 0 additions & 7 deletions stack--current/5-incubator/active/view--chat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,3 @@
A single-direction, block interface for terminal/chat-like interactions.

This package is generic, implementations are expected for terminal, React...


Inspiration:
* https://github.com/andersonba/yve-bot

See also (spotted after I wrote mine)
* https://landbot.io/producthunt/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,125 +3,124 @@
*/
import * as readline from 'node:readline/promises'
import { stdin as input, stdout as output } from 'node:process'
const rl = readline.createInterface({ input, output })

import * as RichText from '@offirmo-private/rich-text-format'
import to_terminal from '@offirmo-private/rich-text-format--to-terminal'

import { type ChatPrimitives, type InputParameters, type SelectParameters } from '../primitives/types.js'
import type { InputStep } from '../steps'
import { Parameters } from '@offirmo-private/storypad/src/types/csf'

const DEBUG = false

const CHAT_CONSOLE: ChatPrimitives<string> = {
export class ChatPrimitivesConsole<ContentType = string | RichText.Document> implements ChatPrimitives<ContentType> {
rli = readline.createInterface({ input, output })

constructor() {
}

get_string_representation(content: ContentType | string): string {
if (typeof content === 'string') return content

if (RichText.isꓽNode(content)) {
return to_terminal(content)
}

throw new Error(`ChatPrimitivesConsole: advanced content not implemented!!`)
}

display_message: async ({msg}) => {
async display_message({ msg }: Parameters<ChatPrimitives<ContentType>['display_message']>[0]) {
DEBUG && console.log('[ChatPrimitives.display_message(…)]')
console.log(msg)
},
console.log(this.get_string_representation(msg))
}

pretend_to_think: async ({duration_ms}) => {
async pretend_to_think({ duration_ms }: Parameters<ChatPrimitives<ContentType>['pretend_to_think']>[0]) {
DEBUG && console.log('[ChatPrimitives.pretend_to_think(${duration_ms})]')

console.log('…')
await new Promise(resolve => setTimeout(resolve, duration_ms))
console.log('↳ ✔')
},
}

pretend_to_work: async ({
msg_before,
duration_ms,
msg_after,
}) => {
DEBUG && console.log(`[ChatPrimitives.pretend_to_work(${duration_ms})]`)

console.log(msg_before)
await new Promise(resolve => setTimeout(resolve, duration_ms))
console.log('↳ ' + msg_after)
},

display_task: async ({
msg_before,
promise,
msg_after,
}) => {
async display_task({
msg_before,
promise,
msg_after,
}: Parameters<ChatPrimitives<ContentType>['display_task']>[0]) {
DEBUG && console.log('[ChatPrimitives.display_task(…)]')

console.log(msg_before)
console.log(this.get_string_representation(msg_before))
let result: any = undefined
let error: Error | undefined = undefined
const success = await promise.then(
(_res) => {
result = _res
return true
},
(_err) => {
error = _err as any // TODO one day coerce to error using error utils
return false
})
console.log('↳ ' + msg_after(success, result || error))
},

input: async <T>({
prompt,
// we ignore the rest in this basic implementation
}: InputParameters<string, T>): Promise<string> => {
(_res) => {
result = _res
return true
},
(_err) => {
error = _err as any // TODO one day coerce to error using error utils
return false
})
console.log('↳ ' + this.get_string_representation(msg_after(success, result || error)))
}

async input<T>({
prompt,
// we ignore the rest in this basic implementation
}: InputParameters<ContentType, T>): Promise<string> {
DEBUG && console.log('[ChatPrimitives.input(…)]')
return rl.question(prompt + ' ')
},

select: async <T>({
prompt,
default_value,
options,
}: SelectParameters<string, T>): Promise<T> => {
return this.rli.question(this.get_string_representation(prompt) + ' ')
}

async select<T>({
prompt,
default_value,
options,
}: SelectParameters<ContentType, T>): Promise<T> {
DEBUG && console.log('[ChatPrimitives.select(…)]')
const keys = Object.keys(options)


let is_valid = false
let answer: T = options[keys[0]!]!.value ?? (keys[0] as any)
do {
console.log(prompt)
console.log(this.get_string_representation(prompt))
keys.forEach((key, index) => {
const option = options[key]!
console.log(`- ${index + 1}. ${option.cta || key}`, (default_value !== undefined && option.value === default_value) ? '(default)' : '')
console.log(`- ${index + 1}. ${this.get_string_representation(option.cta || key)}`, (default_value !== undefined && option.value === default_value) ? '(default)' : '')
})

const raw_input = await rl.question('Your choice? (enter a number) ')
const raw_input = await this.rli.question('Your choice? (enter a number) ')
console.log(`[ChatPrimitives.select(...): you said: "${raw_input}"`)
if (raw_input.trim() === '' && default_value !== undefined) {
answer = default_value
is_valid = true
}
else {
} else {
const choice = parseInt(raw_input.trim(), 10)
if (!Number.isInteger(choice) || choice < 1 || choice > keys.length) {
console.log('Invalid choice, please try again.')
}
else {
} else {
answer = options[keys[choice - 1]!]!.value ?? (keys[choice - 1] as any)
is_valid = true
}
}
} while (!is_valid)
return answer
},
}

spin_until_resolution: async ({promise}) => {
async spin_until_resolution<T>({ promise }: { promise: Promise<T> }): Promise<T> {
DEBUG && console.log('[ChatPrimitives.spin_until_resolution(...)]')

console.log('[ChatPrimitives.spin_until_resolution()] begin…')
await promise
console.log('↳ end.')
return promise
},
}

setup: async () => {
async setup() {
DEBUG && console.log('[ChatPrimitives.setup()]')
},
teardown: async () => {
console.log()
}

async teardown() {
DEBUG && console.log('[ChatPrimitives.teardown()]')
},
this.rli.close()
}
}

export default CHAT_CONSOLE
4 changes: 4 additions & 0 deletions stack--current/5-incubator/active/view--chat/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ export {
// for convenience
PromiseWithProgress,
}

export * from './steps/index.js'
export * from './primitives/index.js'
export * from './loop/index.js'
4 changes: 2 additions & 2 deletions stack--current/5-incubator/active/view--chat/src/loop/demo.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import generator_func from '../__fixtures/tour.js'
import primitives from '../__fixtures/primitives--console.js'
import { ChatPrimitivesConsole } from '../__fixtures/primitives--console.js'

import { create } from './index.js'

const chat = create({
DEBUG: false,
gen_next_step: generator_func() as any,
primitives,
primitives: new ChatPrimitivesConsole(),
})

await chat.start()
25 changes: 15 additions & 10 deletions stack--current/5-incubator/active/view--chat/src/loop/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { type Immutable } from '@offirmo-private/ts-types'
import assert from 'tiny-invariant'

import { type ChatPrimitives } from '../primitives/types.js'
import { type Step, StepType } from '../steps/index.js'
import { type Step, StepType, type TaskProgressStep } from '../steps/index.js'
import { StepsGenerator } from './types.js'
import { create_dummy_progress_promise } from '../utils/index.js'

/////////////////////////////////////////////////

Expand All @@ -13,7 +14,7 @@ interface Options<ContentType> {
primitives: ChatPrimitives<ContentType>

// TODO review! merge?
inter_msg_delay_ms?: number // standard time between steps
//inter_msg_delay_ms?: number // standard time between steps
after_input_delay_ms?: number // time we should pretend to process the user input

DEBUG?: boolean
Expand All @@ -28,7 +29,7 @@ const LIB = 'chat_loop'
function create<ContentType>({
gen_next_step,
primitives,
inter_msg_delay_ms = 0,
//inter_msg_delay_ms = 0,
after_input_delay_ms = 0, // TODO better defaults
DEBUG = false,
DEBUG_to_prettified_str = (x: any) => x, // work with browser
Expand Down Expand Up @@ -101,13 +102,16 @@ function create<ContentType>({
await primitives.display_message({ msg: step.msg })
break

case StepType.perceived_labor:
await primitives.pretend_to_work({
msg_before: step.msg_before || 'Please wait…',
duration_ms: step.duration_ms || 1200, // 200ms = minimum time to be perceived as work
msg_after: step.msg_after || 'Done!',
})
break
case StepType.perceived_labor: {
// we pretend there is a task, so let's use a fake task
const task_step: TaskProgressStep<ContentType, void> = {
type: StepType.progress,
promise: create_dummy_progress_promise({
DURATION_MS: step.duration_ms || 1200, // 200ms = minimum time to be perceived as work
}),
}
return execute_step(task_step)
}

case StepType.progress: {
let result: any = undefined
Expand Down Expand Up @@ -273,3 +277,4 @@ function create<ContentType>({
export {
create,
}
export * from './types.js'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './types.js'
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,12 @@ interface ChatPrimitives<ContentType> {

/////////////////////////////////////////////////
// core primitives
display_message(p: {
msg: ContentType | string,
}): Promise<void>

display_message(p: { msg: ContentType | string }): Promise<void>

// a staple of chat interfaces
// to be used between steps
pretend_to_think(p: {duration_ms: number}): Promise<void>

pretend_to_work(p: {
msg_before: ContentType | string,
duration_ms: number,
msg_after: ContentType | string,
}): Promise<void>
pretend_to_think(p: { duration_ms: number }): Promise<void>

display_task(p: {
msg_before: ContentType | string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ interface SimpleMessageStep<ContentType> extends BaseStep {
msg: ContentType | string
}

// TODO is it redundant with progress?
interface PerceivedLaborStep<ContentType> extends BaseStep {
type: typeof StepType.perceived_labor

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@


Inspiration:
* https://github.com/andersonba/yve-bot

See also (spotted after I wrote mine)
* https://landbot.io/producthunt/index.html
Loading

0 comments on commit d5984cc

Please sign in to comment.