Here is a example code that does what you want, you can choose wether the new values are added on top or at the bottom of column B and C by using push or unshift... I prefer unshift for the reasons I gave in the comment but it's up to you ;-)
function timeline() {
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
if(sh.getActiveRange().getA1Notation()!='A1'){return}
var last = lastRowinCol(sh,'B');
var cellA = sh.getRange('A1').getValues();
var colB = sh.getRange('B1:B'+last).getValues();
var colC = sh.getRange('C1:C'+last).getValues();
// colB.unshift(cellA); // add on top
// colC.unshift([new Date()]);
colB.push(cellA); //add at the bottom
colC.push([new Date()]);
sh.getRange(1,2,colB.length,1).setValues(colB);
sh.getRange(1,3,colC.length,1).setValues(colC);
}
function lastRowinCol(sh,col){
var coldata = sh.getRange(col+'1:'+col).getValues();
for(var c in coldata){if(coldata[c][0]==''){break}}
return c
}
note : there are other ways to implement this but this one is pretty "didactic" I think... using arrays, subfunction call, batch read and write...
Edit: I forgot to mention that you need to assign an onEdit trigger to that function to let it execute automatically.
EDIT 2 : following the very pertinent comment from Mogsdad below I suggest you replace the for-next loop in function lastRowinCol with his code that iterates backwards so that it handles empty cells in the column. Moreover his code has an interesting construction since the loop limits and the condition are in the same statement.
function lastRowinCol(sh,col){
var coldata = sh.getRange(col+'1:'+col).getValues();
for (var c=coldata.length; (c) && coldata[c-1][0]==''; c--) {}
return c
}